home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / stdwin / Ports / mac / event.c < prev    next >
Text File  |  1995-12-21  |  13KB  |  715 lines

  1. /* MAC STDWIN -- EVENT HANDLING. */
  2.  
  3. #include "macwin.h"
  4. #include <Menus.h>
  5. #include <Desk.h>
  6. #include <ToolUtils.h>
  7. #include <AppleEvents.h>
  8. #ifdef CONSOLE_IO
  9. #include <console.h> /* See do_update */
  10. #endif
  11.  
  12. void (*_w_idle_proc)();    /* Function to call in idle loop */
  13.  
  14. void (*_w_high_level_event_proc)(EventRecord *, EVENT *);
  15.             /* Function to call for High Level Events */
  16.  
  17. WINDOW *active= NULL;    /* The active window */
  18.             /* XXX should be a less obvious name */
  19. bool _wm_down;        /* Set if mouse is down in content rect */
  20.  
  21. static EventRecord e;    /* Global, so it's accessible to all subroutines */
  22.             /* XXX the name is too short */
  23.  
  24. /* Function prototypes */
  25.  
  26. STATIC void make_mouse_event _ARGS((EVENT *ep, Point *pwhere));
  27. STATIC void do_idle _ARGS((EVENT *ep));
  28. STATIC void do_update _ARGS((EVENT *ep));
  29. STATIC void do_mouse_down _ARGS((EVENT *ep));
  30. STATIC void do_mouse_up _ARGS((EVENT *ep));
  31. STATIC void do_key _ARGS((EVENT *ep));
  32. STATIC void do_activate _ARGS((EVENT *ep));
  33. STATIC void do_disk _ARGS((EVENT *ep));
  34. STATIC void do_highlevel _ARGS((EVENT *ep));
  35. STATIC void activate _ARGS((WINDOW *win));
  36. STATIC void deactivate _ARGS((void));
  37.  
  38. STATIC void do_click _ARGS((EVENT *ep, WindowPtr w));
  39. STATIC void do_unclick _ARGS((EVENT *ep));
  40. STATIC void do_drag _ARGS((WindowPtr w));
  41. STATIC void do_grow _ARGS((EVENT *ep, WindowPtr w));
  42. STATIC void do_goaway _ARGS((EVENT *ep, WindowPtr w));
  43. STATIC void do_zoom _ARGS((EVENT *ep, WindowPtr w, int code));
  44. STATIC void do_size _ARGS((EVENT *ep, WindowPtr w));
  45.  
  46. static EVENT pushback= {WE_NULL};
  47.  
  48. void
  49. wungetevent(ep)
  50.     EVENT *ep;
  51. {
  52.     pushback= *ep;
  53. }
  54.  
  55. static void
  56. wwaitevent(ep, wait)
  57.     EVENT *ep;
  58.     bool wait;
  59. {
  60.     _wfreeclip();
  61.     if (pushback.type != WE_NULL) {
  62.         *ep= pushback;
  63.         pushback.type= WE_NULL;
  64.         return;
  65.     }
  66.     
  67.     if (_wmenuhilite) {
  68.         HiliteMenu(0);
  69.         _wmenuhilite= FALSE;
  70.     }
  71.     
  72.     if (active == NULL)
  73.         set_arrow();
  74.     else if (active->w != FrontWindow()) {
  75.         /* Somehow we missed a deactivation event.
  76.            Fake one now. */
  77.         ep->type= WE_DEACTIVATE;
  78.         ep->window= active;
  79.         deactivate();
  80.         return;
  81.     }
  82.     
  83.     ep->type= WE_NULL;
  84.     ep->window= NULL;
  85.     
  86.     do {
  87.         if (!GetNextEvent(everyEvent, &e)) {
  88.             if (e.what == nullEvent) {
  89.                 if (wait) do_idle(ep);
  90.                 else return;
  91.             }
  92.         }
  93.         else {
  94.             switch (e.what) {
  95.             case mouseDown:
  96.                 do_mouse_down(ep);
  97.                 break;
  98.             case mouseUp:
  99.                 do_mouse_up(ep);
  100.                 break;
  101.             case keyDown:
  102.             case autoKey:
  103.                 do_key(ep);
  104.                 break;
  105.             case updateEvt:
  106.                 do_update(ep);
  107.                 break;
  108.             case diskEvt:
  109.                 do_disk(ep);
  110.                 break;
  111.             case activateEvt:
  112.                 do_activate(ep);
  113.                 break;
  114.             case kHighLevelEvent:
  115.                 do_highlevel(ep);
  116.                 break;
  117.             }
  118.         }
  119.     } while (ep->type == WE_NULL);
  120.     
  121.     if (ep->window == NULL)
  122.         ep->window= whichwin(FrontWindow());
  123.     if (!_wm_down)
  124.         set_watch();
  125. }
  126.  
  127. int
  128. wpollevent(ep)
  129.         EVENT *ep;
  130. {
  131.         ep->type = WE_NULL;
  132.         wwaitevent(ep, FALSE);
  133.         return ep->type != WE_NULL;
  134. }
  135.  
  136. void
  137. wgetevent(ep)
  138.         EVENT *ep;
  139. {
  140.         wwaitevent(ep, TRUE);
  141. }
  142.  
  143. static void
  144. do_idle(ep)
  145.     EVENT *ep;
  146. {    
  147.     if (checktimer(ep))
  148.         return;
  149.     
  150.     if (_w_idle_proc != NULL)
  151.         (*_w_idle_proc)();
  152.     
  153.     /* The user idle proc may have called wungetevent: */
  154.     if (pushback.type != WE_NULL) {
  155.         *ep= pushback;
  156.         pushback.type= WE_NULL;
  157.         return;
  158.     }
  159.     
  160.     SystemTask();
  161.     
  162.     if (active != NULL) {
  163.         Point where;
  164.         Rect r;
  165.         
  166.         where= e.where;
  167.         SetPort(active->w);
  168.         GlobalToLocal(&where);
  169.         if (_wm_down) {
  170.             autoscroll(active, where.h, where.v);
  171.             make_mouse_event(ep, &where);
  172.             return;
  173.         }
  174.         getwinrect(active, &r);
  175.         if (PtInRect(PASSPOINT where, &r)) {
  176.             if (e.modifiers & optionKey)
  177.                 set_hand();
  178.             else
  179.                 set_applcursor();
  180.         }
  181.         else
  182.             set_arrow();
  183.         blinkcaret(active);
  184.     }
  185. }
  186.  
  187. static void
  188. do_update(ep)
  189.     EVENT *ep;
  190. {
  191.     WINDOW *win;
  192.     Rect r;
  193.     
  194.     win= whichwin((WindowPtr) e.message);
  195.     if (win == NULL) {
  196.         /* Update event for a window not created by STDWIN
  197.            (not a Desk Accessory -- these are taken care of
  198.            by GetNextEvent or at some other secret place.)
  199.            This is a problem: if we ignore it, it will come
  200.            back forever, so we'll never be idle again. */
  201. #ifdef CONSOLE_IO
  202.         /* Most likely, under THINK C, it is the console
  203.            window.  We can force the window to repaint itself
  204.            by calling any console function.  A rather harmless
  205.            one is cgetxy.  Use stderr as the one least likely
  206.            to be redirected. */
  207.         int x, y;
  208.         if (stderr->window)
  209.             cgetxy(&x, &y, stderr);
  210. #endif
  211.         return;
  212.     }
  213.     _wupdate(win, &r);
  214.     if (win->drawproc == NULL && !EmptyRect(&r)) {
  215.         ep->type= WE_DRAW;
  216.         ep->window= win;
  217.         ep->u.area.left= r.left;
  218.         ep->u.area.top= r.top;
  219.         ep->u.area.right= r.right;
  220.         ep->u.area.bottom= r.bottom;
  221.     }
  222. }
  223.  
  224. static void
  225. do_mouse_down(ep)
  226.     EVENT *ep;
  227. {
  228.     WindowPtr w;
  229.     int code= FindWindow(PASSPOINT e.where, &w);
  230.     
  231.     if (code != inContent && code != inSysWindow)
  232.         set_arrow();
  233.     switch (code) {
  234.     case inMenuBar:
  235.         _wdo_menu(ep, MenuSelect(PASSPOINT e.where));    
  236.         break;
  237.     case inSysWindow:
  238.         SystemClick(&e, w);
  239.         break;
  240.     case inContent:
  241.         do_click(ep, w);
  242.         break;
  243.     case inDrag:
  244.         do_drag(w);
  245.         break;
  246.     case inGrow:
  247.         do_grow(ep, w);
  248.         break;
  249.     case inGoAway:
  250.         do_goaway(ep, w);
  251.         break;
  252.     case inZoomIn:
  253.     case inZoomOut:
  254.         do_zoom(ep, w, code);
  255.         break;
  256.     }
  257. }
  258.  
  259. static void
  260. do_mouse_up(ep)
  261.     EVENT *ep;
  262. {
  263.     do_unclick(ep);
  264. }
  265.  
  266. static void
  267. do_key(ep)
  268.     EVENT *ep;
  269. {
  270.     int c= e.message & charCodeMask;
  271.     
  272.     if (e.modifiers & cmdKey) {
  273.         if (c == '.') {
  274.             ep->type= WE_COMMAND;
  275.             ep->u.command= WC_CANCEL;
  276.         }
  277.         else {
  278.             long menu_item= MenuKey(c);
  279.             if (HiWord(menu_item) != 0) {
  280.                 _wdo_menu(ep, menu_item);
  281.             }
  282.             else {
  283.                 ep->type= WE_KEY;
  284.                 ep->u.key.code= c;
  285.                 ep->u.key.mask= WM_META;
  286.                 /* Should filter out arrow keys? */
  287.             }
  288.         }
  289.     }
  290.     else {
  291.         ep->type= WE_COMMAND;
  292.         switch (c) {
  293.         
  294.         default:
  295.             ObscureCursor();
  296.             ep->type= WE_CHAR;
  297.             ep->u.character= c;
  298.             break;
  299.         
  300.         case LEFT_ARROW:
  301.         case RIGHT_ARROW:
  302.         case UP_ARROW:
  303.         case DOWN_ARROW:
  304.             ep->u.command= c-LEFT_ARROW + WC_LEFT;
  305.             break;
  306.         
  307.         case '\b':
  308.             ObscureCursor();
  309.             ep->u.command= WC_BACKSPACE;
  310.             break;
  311.         
  312.         case '\t':
  313.             ObscureCursor();
  314.             ep->u.command= WC_TAB;
  315.             break;
  316.         
  317.         case '\r':
  318.         case ENTER_KEY:
  319.             ep->u.command= WC_RETURN;
  320.             break;
  321.         
  322.         }
  323.     }
  324. }
  325.  
  326. static void
  327. do_disk(ep)
  328.     EVENT *ep;
  329. {
  330.     /* XXX Disk events not implemented -- who cares. */
  331. }
  332.  
  333. static void
  334. do_highlevel(ep)
  335.     EVENT *ep;
  336. {
  337.     if (_w_high_level_event_proc != NULL)
  338.         (*_w_high_level_event_proc)(&e, ep);
  339. }
  340.  
  341. /* XXX Need to be easier for cases where we seem to have missed events */
  342.  
  343. static void
  344. do_activate(ep)
  345.     EVENT *ep;
  346. {
  347.     WINDOW *win= whichwin((WindowPtr)e.message);
  348.     
  349.     if (win == NULL) {
  350.         /* dprintf("(de)activate evt for alien window"); */
  351.         return;
  352.     }
  353.     
  354.     if (e.modifiers & activeFlag) { /* Activation */
  355.         if (active != NULL) {
  356.             /* Perhaps reactivation after modal dialog */
  357.             if (active == win)
  358.                 return;
  359.             /* If we get here we've missed a
  360.                deactivate event... */
  361.             /* dprintf("activate without deactivate"); */
  362.         }
  363.         activate(win);
  364.         ep->type= WE_ACTIVATE;
  365.         ep->window= active;
  366.     }
  367.     else { /* Deactivation */
  368.         if (win != active) {
  369.             /* Spurious deactivation event.
  370.                This always happens when we open
  371.                two or more windows without intervening
  372.                call to wgetevent().
  373.                Perhaps an conscious hack in the
  374.                ROM to "help" programs that believe
  375.                windows are created active? */
  376.             return;
  377.         }
  378.         ep->type= WE_DEACTIVATE;
  379.         ep->window= active;
  380.         deactivate();
  381.     }
  382. }
  383.  
  384. static void
  385. deactivate()
  386. {
  387.     SetPort(active->w);
  388.     rmcaret(active);
  389.     hidescrollbars(active);
  390.     rmlocalmenus(active);
  391.     _wgrowicon(active);
  392.     active= NULL;
  393.     set_arrow();
  394. }
  395.  
  396. static void
  397. activate(win)
  398.     WINDOW *win;
  399. {
  400.     if (active != NULL)
  401.         deactivate();
  402.     if (win != NULL) {
  403.         SetPort(win->w);
  404.         active= win;
  405.         showscrollbars(win);
  406.         addlocalmenus(active);
  407.         valid_border(win->w); /* Avoid flicker when window pops up */
  408.     }
  409. }
  410.  
  411. static void
  412. do_click(ep, w)
  413.     EVENT *ep;
  414.     WindowPtr w;
  415. {
  416.     WINDOW *win= whichwin(w);
  417.     Point where;
  418.     int pcode;
  419.     ControlHandle bar;
  420.     
  421.     if (win == NULL) {
  422.         /* dprintf("click in alien window"); */
  423.         return;
  424.     }
  425.     if (win != active) {
  426.         set_arrow();
  427.         if (e.modifiers & optionKey) {
  428.             /* Option-click sends a window behind. */
  429.             SendBehind(w, (WindowPtr) NULL);
  430.         }
  431.         else
  432.             SelectWindow(win->w);
  433.         return;
  434.         /* Let activate events do the rest. */
  435.     }
  436.     where= e.where;
  437.     SetPort(win->w);
  438.     GlobalToLocal(&where);
  439.     pcode= FindControl(PASSPOINT where, w, &bar);
  440.     if (pcode != 0) {
  441.         set_arrow();
  442.         do_scroll(&where, win, bar, pcode);
  443.     }
  444.     else {
  445.         Rect r;
  446.         
  447.         getwinrect(win, &r);
  448.         if (PtInRect(PASSPOINT where, &r)) {
  449.             if (e.modifiers & optionKey) {
  450.                 set_hand();
  451.                 dragscroll(win,
  452.                     where.h, where.v,
  453.                     e.modifiers & shiftKey);
  454.             }
  455.             else {
  456.                 set_applcursor();
  457.                 make_mouse_event(ep, &where);
  458.             }
  459.         }
  460.     }
  461. }
  462.  
  463. static void
  464. do_unclick(ep)
  465.     EVENT *ep;
  466. {
  467.     if (active != NULL) {
  468.         Point where;
  469.         
  470.         where= e.where;
  471.         SetPort(active->w);
  472.         GlobalToLocal(&where);
  473.         make_mouse_event(ep, &where);
  474.     }
  475. }
  476.  
  477. static void
  478. do_drag(w)
  479.     WindowPtr w;
  480. {
  481.     if (e.modifiers & optionKey) {
  482.         /* Nonstandard: option-click sends a window behind. */
  483.         SendBehind(w, (WindowPtr) NULL);
  484.     }
  485.     else {
  486.         Rect r;
  487.         
  488.         r= screen->portRect;
  489.         r.top += MENUBARHEIGHT;
  490.         InsetRect(&r, 4, 4);
  491.         DragWindow(w, PASSPOINT e.where, &r);
  492.     }
  493. }
  494.  
  495. static void
  496. do_grow(ep, w)
  497.     EVENT *ep;
  498.     WindowPtr w;
  499. {
  500.     Rect r;
  501.     long reply;
  502.     WINDOW *win = whichwin(w);
  503.     
  504.     /* Don't mess at all with non-stdwin windows */
  505.     if (win == NULL)
  506.         return;
  507.     
  508.     /* Set minimal window size --
  509.       1x1 at least, plus space needed for scroll bars */
  510.     r.left = LSLOP + 1 + RSLOP;
  511.     r.top = 1;
  512.     if (win->hbar != NULL)
  513.         r.left = 3*BAR;
  514.     if (win->vbar != NULL)
  515.         r.top = 3*BAR;
  516.     if (win->vbar != NULL)
  517.         r.left += BAR;
  518.     if (win->hbar != NULL)
  519.         r.top += BAR;
  520.     
  521.     /* Windows may become as large as the user can get them,
  522.        within reason -- the limit 0x7000 should avoid integer
  523.        overflow in QuickDraw. */
  524.     r.right = r.bottom = 0x7000;
  525.     
  526.     reply= GrowWindow(w, PASSPOINT e.where, &r);
  527.     if (reply != 0) {
  528.         SetPort(w);
  529.         inval_border(w);
  530.         SizeWindow(w, LoWord(reply), HiWord(reply), TRUE);
  531.         do_size(ep, w);
  532.     }
  533. }
  534.  
  535. static void
  536. do_goaway(ep, w)
  537.     EVENT *ep;
  538.     WindowPtr w;
  539. {
  540.     /* XXX shouldn't mess at all with non-stdwin windows */
  541.     
  542.     if (TrackGoAway(w, PASSPOINT e.where)) {
  543.         ep->type= WE_CLOSE;
  544.         ep->window= whichwin(w);
  545.     }
  546. }
  547.  
  548. static void
  549. do_zoom(ep, w, code)
  550.     EVENT *ep;
  551.     WindowPtr w;
  552.     int code;
  553. {
  554.     /* XXX shouldn't mess at all with non-stdwin windows */
  555.     
  556.     /* This code will never be reached on a machine
  557.        with old (64K) ROMs, because FindWindow will
  558.        never return inZoomIn or inZoomOut.
  559.        Therefore, no check for new ROMs is necessary.
  560.        A warning in Inside Macintosh IV says that
  561.        it is necessary to make the zoomed window
  562.        the current GrafPort before calling ZoomWindow.
  563.        True enough, it fails spectacularly otherwise,
  564.        but still this looks like a bug to me - there
  565.        are no similar requirements for SizeWindow
  566.        or DragWindow. */
  567.     
  568.     SetPort(w);
  569.     if (TrackBox(w, PASSPOINT e.where, code)) {
  570.         inval_border(w);
  571.         ZoomWindow(w, code, TRUE);
  572.         do_size(ep, w);
  573.     }
  574. }
  575.  
  576. /* do_size assumes w is already the current grafport */
  577.  
  578. static void
  579. do_size(ep, w)
  580.     EVENT *ep;
  581.     WindowPtr w;
  582. {
  583.     WINDOW *win= whichwin(w);
  584.     
  585.     if (win == NULL) {
  586.         /* dprintf("alien window resized"); */
  587.         return;
  588.     }
  589.     inval_border(w);
  590.     movescrollbars(win);
  591.     ep->type= WE_SIZE;
  592.     ep->window= win;
  593.     _wfixorigin(win);
  594. }
  595.  
  596. void
  597. inval_border(w)
  598.     WindowPtr w;
  599. {
  600.     Rect r;
  601.     WINDOW *win = whichwin(w);
  602.     
  603.     if (win->vbar != NULL) {
  604.         r = w->portRect;
  605.         r.left = r.right - BAR;
  606.         InvalRect(&r);
  607.     }
  608.     if (win->hbar != NULL) {
  609.         r = w->portRect;
  610.         r.top = r.bottom - BAR;
  611.         InvalRect(&r);
  612.     }
  613. }
  614.  
  615. void
  616. valid_border(w)
  617.     WindowPtr w;
  618. {
  619.     Rect r;
  620.     WINDOW *win = whichwin(w);
  621.     
  622.     if (win->vbar != NULL) {
  623.         r = w->portRect;
  624.         r.left = r.right - BAR;
  625.         ValidRect(&r);
  626.     }
  627.     if (win->hbar != NULL) {
  628.         r = w->portRect;
  629.         r.top = r.bottom - BAR;
  630.         ValidRect(&r);
  631.     }
  632. }
  633.  
  634. /* Variables needed in click and move detection. */
  635.  
  636. static int m_h, m_v;        /* Doc. coord. of last mouse evt. */
  637. static long m_when;        /* TickCount of last mouse evt. */
  638. static int m_clicks;        /* N-fold click stage */
  639.  
  640. static void
  641. make_mouse_event(ep, pwhere)
  642.     EVENT *ep;
  643.     Point *pwhere;        /* Mouse pos. in local coord. */
  644. {
  645.     WINDOW *win= active;
  646.     int h= pwhere->h + win->orgh;
  647.     int v= pwhere->v + win->orgv;
  648.     int dh= h - m_h;
  649.     int dv= v - m_v;
  650.     int mask;
  651.     
  652.     if (m_clicks != 0 && dh*dh + dv*dv > CLICK_DIST*CLICK_DIST)
  653.         m_clicks= 0;    /* Moved too much for a click */
  654.     
  655.     if (e.what == mouseDown) {
  656.         if (e.when > m_when + GetDblTime())
  657.             m_clicks= 1;
  658.         else
  659.             ++m_clicks;
  660.         ep->type= WE_MOUSE_DOWN;
  661.         _wm_down= TRUE;
  662.     }
  663.     else if (e.what == mouseUp) {
  664.         if (!_wm_down)
  665.             return;
  666.         ep->type= WE_MOUSE_UP;
  667.         _wm_down= FALSE;
  668.     }
  669.     else {
  670.         if (!_wm_down || m_clicks > 0 || (dh == 0 && dv == 0))
  671.             return;
  672.         ep->type= WE_MOUSE_MOVE;
  673.     }
  674.     mask= (ep->type == WE_MOUSE_UP) ? 0 : WM_BUTTON1;
  675.     if (e.modifiers & cmdKey)
  676.         mask |= WM_META;
  677.     if (e.modifiers & shiftKey)
  678.         mask |= WM_SHIFT;
  679.     if (e.modifiers & alphaLock)
  680.         mask |= WM_LOCK;
  681.     if (e.modifiers & optionKey)
  682.         mask |= WM_OPTION;
  683.     if (e.modifiers & controlKey)
  684.         mask |= WM_CONTROL;
  685.     ep->u.where.h= m_h= h;
  686.     ep->u.where.v= m_v= v;
  687.     ep->u.where.clicks= m_clicks;
  688.     ep->u.where.button= 1;
  689.     ep->u.where.mask= mask;
  690.     ep->window= win;
  691.     m_when= e.when;
  692. }
  693.  
  694. /* Reset the mouse state.
  695.    Called when a dialog is started. */
  696.  
  697. void
  698. _wresetmouse()
  699. {
  700.     _wm_down= FALSE;
  701. }
  702.  
  703. void
  704. wsetactive(win)
  705.     WINDOW *win;
  706. {
  707.     SelectWindow(win->w);
  708. }
  709.  
  710. WINDOW *
  711. wgetactive()
  712. {
  713.     return whichwin(FrontWindow());
  714. }
  715.